package org.dxw.common.aspect;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.dxw.common.ano.MethodLog;
import org.dxw.vo.SysLogVO;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @description:
 * @author: dxw
 * @create: 2022-04-04 22:49
 **/
@Aspect  // 使用@Aspect注解声明一个切面
@Component
@Slf4j
public class LogAspect {

    /**
     * 这里我们使用注解的形式
     * 当然，我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
     * 切点表达式:   execution(...)
     */
    @Pointcut("@annotation(org.dxw.common.ano.MethodLog)")
    public void logPointCut() {}

    /**
     * 环绕通知 @Around  ， 当然也可以使用 @Before (前置通知)  @After (后置通知)
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        Object result = point.proceed();
        long time = System.currentTimeMillis() - beginTime;
        try {
            handleLog(point, time);
        } catch (Exception e) {
        }
        return result;
    }

    /**
     * 处理日志
     * @param joinPoint
     * @param time
     */
    private void handleLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        SysLogVO sysLogVO = new SysLogVO();
        sysLogVO.setExeuTime(time);
        Date now = Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
        sysLogVO.setCreateDate(now);
        MethodLog logAnno = ObjectUtil.defaultIfNull(method.getAnnotation(MethodLog.class), method.getClass().getAnnotation(MethodLog.class));
        if(logAnno != null){
            //注解上的描述
            sysLogVO.setRemark(logAnno.value());
        }
        //请求的 类名、方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLogVO.setClassName(className);
        sysLogVO.setMethodName(methodName);
        //请求的参数
        Object[] args = joinPoint.getArgs();
        try{
            List<Object> list = new ArrayList<>();
            for (Object o : args) {
                if(o instanceof HttpServletRequest || o instanceof HttpServletResponse) continue;
                list.add((o));
            }
            sysLogVO.setParams(list);
            log.info(JSON.toJSONString(sysLogVO));
        }catch (Exception e){ }
    }




}